package br.org.bertol.mestrado.engine;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * Enum com os objetivos.
 * @author contaqualquer
 */
public enum Objective {
    /**
     * Objetivo Dependência.
     */
    DEPEDENCIA {

        /***/
        private List<List<Integer>> matrix = new ArrayList<List<Integer>>();

        @Override
        public List<List<Integer>> getWeekConstraint() {
            return matrix;
        }

        @Override
        public void loadParameters(final String source, final String system)
                throws IOException {

            matrix = readInput(source, system, "_depe.txt");
        }

        @Override
        public int getWeekConstraintHeight(final int classe,
                final int constraint) {
            return 1;
        }
        },
    /**
     * Objetivo Método.
     */
    METODO {

        /***/
        private List<List<Integer>> matrix = new ArrayList<List<Integer>>();

        @Override
        public List<List<Integer>> getWeekConstraint() {
            return matrix;
        }

        @Override
        public void loadParameters(final String source, final String system)
                throws IOException {

            matrix = readInput(source, system, "_meth.txt");
        }

        @Override
        public int getWeekConstraintHeight(final int classe,
                final int constraint) {
            return matrix.get(classe - 1).get(constraint);
        }
        },
    /**
     * Objetivo Atributo.
     */
    ATRIBUTO {

        /***/
        private List<List<Integer>> matrix = new ArrayList<List<Integer>>();

        @Override
        public List<List<Integer>> getWeekConstraint() {
            return matrix;
        }

        @Override
        public void loadParameters(final String source, final String system)
                throws IOException {

            matrix = readInput(source, system, "_attr.txt");
        }

        @Override
        public int getWeekConstraintHeight(final int classe,
                final int constraint) {
            return matrix.get(classe - 1).get(constraint);
        }
        };

    /**
     * Lista de restrições fortes.
     * @return Lista
     */
    public abstract List<List<Integer>> getWeekConstraint();

    /**
     * Avalia o peso da violação de uma restrição forte, se ouver.
     * @param classe Classe a ser avaliada
     * @param constraint Classe restrição da uma determinada classe
     * @return O peso da violação
     */
    public abstract int getWeekConstraintHeight(final int classe,
            int constraint);

    /**
     * Carrega os parâmetros de inicialização.
     * @param source Caminho de origem
     * @param system Sistema a ser carregado
     * @throws IOException Caso erro ao carregar
     */
    public abstract void loadParameters(final String source,
            final String system) throws IOException;

    /**
     * @param objectivesNames
     *            Lista de objetivos
     * @return Array com os objetivos passados como par�mtros.
     */
    public static Objective[] valueOf(final String... objectivesNames) {
        final Objective[] objectives = new Objective[objectivesNames.length];

        for (int i = 0; i < objectivesNames.length; i++) {
            objectives[i] = Objective.valueOf(objectivesNames[i]);
        }

        return objectives;
    }

    /**
     * Le as restrições fortes para problema de classes.
     * @param source
     *            Caminho de entrada
     * @param system
     *            Sistema
     * @return Restrições
     * @throws IOException
     *             Erro ao ler arquivo
     */
    public static List<List<Integer>> loadStrongConstraint(final String source,
            final String system) throws IOException {
        return readInput(source, system, "_prece.txt");
    }

    /**
     * Lêe arquivo com as entradas.
     * @param source
     *            Caminho onde está o arquivo
     * @param system
     *            Sistema a ser lido
     * @param typeInput
     *            Tipo de entrada
     * @return Dados de entrada
     * @throws IOException
     *             Erro ao ler arquivo
     */
    protected static List<List<Integer>> readInput(final String source,
            final String system, final String typeInput) throws IOException {
        final List<List<Integer>> colluns = new ArrayList<List<Integer>>();

        final File inputFile = new File(source + "/" + system + typeInput);

        if (!inputFile.exists()) {
            return colluns;
        }

        final Scanner reader = new Scanner(inputFile);

        // caminha pela matriz de entrada
        while (reader.hasNext()) {
            final String[] input = reader.nextLine().split(" ");

            final List<Integer> row = new ArrayList<Integer>();

            // adiciona as classes a uma lista
            for (String c : input) {
                row.add(Integer.parseInt(c));
            }
            colluns.add(row);
        }

        return colluns;
    }
}
